#include<muduo/net/TcpServer.h>
#include<muduo/net/EventLoop.h>
#include<muduo/base/CountDownLatch.h>
#include<memory>
#include<string>
#include<iostream>

class TcpServer
{
public:
    TcpServer(const uint16_t port, const std::string& name, bool reusePort, const std::string& ip)
        :_eventLoop(new muduo::net::EventLoop()) 
        {
            auto flag = muduo::net::TcpServer::Option::kNoReusePort;
            if (reusePort)
            {
                flag = muduo::net::TcpServer::Option::kReusePort;
            }
            _ser = std::make_shared<muduo::net::TcpServer>(_eventLoop.get(), muduo::net::InetAddress(ip, port), name, flag);
        }

    // typedef std::function<void (const TcpConnectionPtr&)> ConnectionCallback;
    // typedef std::function<void (const TcpConnectionPtr&, Buffer*, Timestamp)> MessageCallback;
    bool init(const muduo::net::ConnectionCallback& conn_cb, const muduo::net::MessageCallback& mess_cb, uint8_t thread_nums)
    {
        if (_ser)
        {
            _ser->setConnectionCallback(conn_cb);
            _ser->setMessageCallback(mess_cb);
            _ser->setThreadNum(thread_nums); // 除主线程外，另外的IO线程数 // 内部会调用 EventLoopThreadPool::setThreadNum()
            if (thread_nums > 0)
            {
                _latch = std::make_unique<muduo::CountDownLatch>(thread_nums);
                // typedef std::function<void(EventLoop*)> ThreadInitCallback;
                _ser->setThreadInitCallback(std::bind(&TcpServer::thiredInitCallback, this, std::placeholders::_1));
            }
            return true;
        }
        return false;
    }

    void start()
    {
        _ser->start();
        _latch->wait(); // 阻塞等待所以线程初始化完后继续
        _eventLoop->loop();
    }
private:
    void thiredInitCallback(muduo::net::EventLoop*)
    {
        _latch->countDown();
    }
private:
    std::unique_ptr<muduo::net::EventLoop> _eventLoop; // 事件循环监控
    std::shared_ptr<muduo::net::TcpServer> _ser;
    std::unique_ptr<muduo::CountDownLatch> _latch; // 多线程同步计数器
};



// echo
class EchoServer : public TcpServer
{
public:
    EchoServer(const uint16_t port, const std::string& name = "Server", bool reusePort = false, const std::string& ip = "0.0.0.0")
        :TcpServer(port, name, reusePort, ip)
    {}


    void closeCallBack(const muduo::net::TcpConnectionPtr& conn)
    {
        std::cout << conn->getTcpInfoString() << "连接断开！" << std::endl;
    }
public:
    void connected(const muduo::net::TcpConnectionPtr& conn)
    {
        if (conn->connected())
        {
            std::cout << conn->getTcpInfoString() << " 连接到本服务端。" << std::endl;
            conn->setCloseCallback(std::bind(&EchoServer::closeCallBack, this, std::placeholders::_1));
        }
    }

    void echo(const muduo::net::TcpConnectionPtr& conn, muduo::net::Buffer* buffer, muduo::Timestamp)
    {
        if (conn->connected())
        {
            std::string tmp = buffer->retrieveAllAsString();
            //......

            std::cout << "收到：" << conn->getTcpInfoString() << " > " << tmp << std::endl;

            conn->send(tmp);
        }
    }
};

int main()
{
    EchoServer Echo(9090);
    bool ret = Echo.init(std::bind(&EchoServer::connected, &Echo, std::placeholders::_1), 
            std::bind(&EchoServer::echo, &Echo, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3),
            3);
    if (!ret)
    {
        std::cout << "服务启动失败！" << std::endl;
        return -1;
    }

    Echo.start();
    return 0;
}